﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Web;
using System.Data;

namespace Twi.COMMON.Core
{
    /*
     * CopyRight:©2012 Twilight软件开发工作室版权所有
     * Author:xuzhihong
     * Create Date: 2012-07-24
     * Description: 根据Web请求的信息，动态执行方法
     */
    public class TwiAjaxHelper
    {
        static string TwiPageNS = TwiConfigHelper.GetAppSettingValue("TwiPageNS");
        private static string TwiIgnoreRightMN2 = TwiConfigHelper.GetAppSettingValue("TwiIgnoreRightMN2");
        private static Dictionary<string, Assembly> TwiPagesAssemblies = new Dictionary<string, Assembly>();
        private static readonly BindingFlags ActionBindingFlags = BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase;
        /// <summary>
        /// 初始化加载
        /// </summary>
        static TwiAjaxHelper()
        {
            TwiPageNS = string.IsNullOrEmpty(TwiPageNS) ? "Twi.Pages" : TwiPageNS;

            //返回所有页编译都必须引用的程序集引用的列表
            var assemblies = System.Web.Compilation.BuildManager.GetReferencedAssemblies();
            foreach (Assembly assembly in assemblies)
            {
                //如果没有指定前缀则加载所有dll,否则加载指定前缀的dll
                if ((TwiPageNS == "NoPrefix" && !assembly.FullName.StartsWith("System")) || assembly.FullName.StartsWith(TwiPageNS))
                {
                    TwiPagesAssemblies.Add(assembly.GetName().Name, assembly);
                }
            }
        }

        /// <summary>
        /// 返回请求信息【前台调用使用】
        /// </summary>
        /// <param name="context"></param>
        /// <remarks>请求包含：【模块名缩写，如SM】ModuleName:(mn)、【类名】ClassName(cn)、【方法名】MethodName(mn2)、【是否为静态方法】isStatic、及对应参数【参数名和方法中对应】</remarks>
        /// <returns></returns>
        public static string GetResponse(HttpContext context)
        {
            TwiReturn twi = new TwiReturn();
            string strReturn = "";  //最后返回的twiReturn字符串
            bool hasWriteStrReturnLog = false; //是否已经写过strReturn日志，当查询数据较多的时候，在序列化之前写简化内容的日志
            try
            {                
                TwiLogHelper.Begin("TwiAjaxHelper.GetResponse开始调用...");                
                if (context.Request.UrlReferrer != null)
                {
                    TwiLogHelper.None("请求地址：" + context.Request.UrlReferrer.AbsoluteUri);
                    TwiLogHelper.Info("浏览器信息：" + TwiNetHelper.GetHttpUserAgent());
                }

                TwiLogHelper.Info("开始检测IP访问限制...");
                string twiIpsCheckMsg = "";
                twi.success = TwiNetHelper.CheckIsAllowIp(ref twiIpsCheckMsg);
                TwiLogHelper.Info(twiIpsCheckMsg);
                if (!twi.success)
                {
                    throw new Exception(twiIpsCheckMsg);
                }

                //Dictionary<string, dynamic> twiData= TwiJsonHelper.JsonToDictionary(context.Request["TwiData"]);
                string assemblyName = TwiPageNS;
                string strTypeName = string.Format("{0}.{1}", TwiPageNS, context.Request["cn"]);
                if (!string.IsNullOrEmpty(context.Request["mn"]))
                {
                    assemblyName = string.Format("{0}.{1}", TwiPageNS, context.Request["mn"]);
                    strTypeName = string.Format("{0}.{1}.{2}", TwiPageNS, context.Request["mn"], context.Request["cn"]);
                }

                if (TwiPageNS == "NoPrefix")
                {
                    strTypeName = context.Request["cn"];
                    assemblyName = context.Request["mn"];
                    strTypeName = string.Format("{0}.{1}", context.Request["mn"], context.Request["cn"]);
                }

                //写请求参数日志
                TwiAjaxHelper.WriteRequestFormLog(context);

                Assembly ass = GetAssembly(assemblyName);
                Type t = ass.GetType(strTypeName);
                MethodInfo methodInfo = t.GetMethod(context.Request["mn2"], ActionBindingFlags);
                if (methodInfo == null)
                {
                    throw new Exception(string.Format("{0}中未找到方法{1}", strTypeName, context.Request["mn2"]));
                }
                ParameterInfo[] paras = methodInfo.GetParameters();

                //参数和赋值
                object[] objParas = null;
                if (paras.Length > 0)
                {
                    objParas = new object[paras.Length];
                }
                //数据标识 主要是为EasyUI标识
                string dataSign = context.Request["dataSign"];

                for (int i = 0; i < paras.Length; i++)
                {
                    ParameterInfo pi = paras[i];
                    if (pi.Name == "paging") //如果存在参数名为paging【PagingCondition实例】的参数
                    {
                        PagingCondition paging = new PagingCondition();
                        try
                        {
                            //dataSign未配置取Twi规则
                            if (string.IsNullOrEmpty(dataSign)) {
                                string pageSize = context.Request["pageSize"];
                                paging.startIndex = Convert.ToInt32(context.Request["startIndex"]);
                                paging.pageSize = string.IsNullOrEmpty(pageSize) ? paging.pageSize : Convert.ToInt32(pageSize);
                            }
                            else if (dataSign == "EasyUI")
                            {
                                string rows = context.Request["rows"];
                                paging.pageSize = string.IsNullOrEmpty(rows) ? paging.pageSize : Convert.ToInt32(rows);
                                int currentPage = Convert.ToInt32(context.Request["page"]);
                                currentPage = currentPage == 0 ? 1 : currentPage;
                                paging.startIndex = (currentPage - 1) * paging.pageSize;
                            }
                            else if (dataSign == "Extjs")
                            {
                                string limit = context.Request["limit"];
                                paging.startIndex = Convert.ToInt32(context.Request["start"]);
                                paging.pageSize = string.IsNullOrEmpty(limit) ? paging.pageSize : Convert.ToInt32(limit);
                            };
                        }
                        catch
                        {
                            //取默认的分页设置
                        }
                        if (context.Request["needPaging"] == null || context.Request["needPaging"] == "false" || context.Request["needPaging"] == "0")
                        {
                            paging.needPaging = false;
                        }
                        objParas[i] = paging;
                    }
                    else
                    {
                        objParas[i] = context.Request[pi.Name];
                    }
                }

                object obj = null;
                if (string.IsNullOrEmpty(context.Request["isStatic"]) || context.Request["isStatic"] == "false" || context.Request["isStatic"] == "0")
                {
                    obj = Activator.CreateInstance(t);
                }

                //先判断权限                
                twi.hasRight = true;
                twi.success = true;
                try
                {
                    string mn2Format = string.Format("{0}.{1}.{2}", context.Request["mn"], context.Request["cn"], context.Request["mn2"]);
                    if (CheckMn2IsOnRight(mn2Format))
                    {
                        UserContext.CheckRight(ref twi);
                    }
                }
                catch (System.Exception ex)
                {
                    twi.success = false;
                    twi.errors = ex.Message;
                    twi.data = "";
                    strReturn = JSSerialize.Serialize(twi);
                }

                if (twi.success)
                {
                    //再查询数据
                    dynamic dyReturn = methodInfo.Invoke(obj, objParas);
                    Type rtnType = dyReturn.GetType();

                    if (typeof(DataTable) == rtnType)
                    {
                        strReturn = TwiJsonHelper.DataTableToTwiJson(dyReturn, ref twi);
                        //长日志可能写成短日志
                        WriteLongToShortLog(twi, ref hasWriteStrReturnLog);
                    }
                    else if (typeof(TwiReturn) == rtnType)
                    {
                        strReturn = JSSerialize.Serialize(dyReturn);
                        //长日志可能写成短日志
                        WriteLongToShortLog(dyReturn as TwiReturn, ref hasWriteStrReturnLog);
                    }
                    else if (typeof(string) == rtnType)
                    {
                        //返回自定义JSON格式
                        strReturn = dyReturn;
                    }
                    else
                    {
                        //如果是其他类型，请返回TwiReturn类型（将TwiReturn.data的值设置为你要返回的值）
                        throw new Exception("不符合规范：业务逻辑层的方法必须统一返回DataTable、TwiReturn、string之间的一种");
                    }

                    if (dataSign == "EasyUI")
                    {
                        strReturn = strReturn.Replace("\"data\":", "\"rows\":");
                        strReturn = strReturn.Replace("\"totalCount\":", "\"total\":");
                        strReturn = strReturn.Replace(",\"_parentId\":\"\"", "");
                        TwiLogHelper.Info("dataSign == EasyUI返回对象替换：data->rows,totalCount->total;_parentId");
                    }
                }
            }
            catch (System.Exception ex)
            {
                twi.success = false;
                twi.hasRight = true;
                twi.errors = ex.Message;
                if (ex.InnerException != null)
                {
                    twi.errors += "-〉内部错误为：" + ex.InnerException.Message;
                }
                strReturn = JSSerialize.Serialize(twi);               
                TwiLogHelper.WriteTwiReturnLog(twi, TwiLogGrade.Error);                
            }
            //写日志
            if (!hasWriteStrReturnLog)
            {
                TwiLogHelper.Info("返回JSON字符串：" + strReturn);
            }
            TwiLogHelper.End("TwiAjaxHelper.GetResponse执行完成！\r\n=================================================================");
            return strReturn;
        }

        /// <summary>
        /// 根据程序集名获取对应的Assembly
        /// </summary>
        /// <param name="assemblyName"></param>
        /// <returns></returns>
        public static Assembly GetAssembly(string assemblyName)
        {
            //先检测bin文件夹下，如果没有，则会再检测C盘对应的bin
            //Twi.Pages生成的dll要生成到bin文件夹中.
            if (!TwiPagesAssemblies.ContainsKey(assemblyName))
            {
                string binPath = HttpRuntime.CodegenDir;
                string[] directories = System.IO.Directory.GetFiles(binPath, assemblyName + ".dll", System.IO.SearchOption.AllDirectories);
                if (directories.Length == 0)
                {
                    throw new Exception("未找到所需文件：" + assemblyName + ".dll");
                }
                Assembly ass = Assembly.LoadFrom(directories[0]);
                TwiPagesAssemblies.Add(assemblyName, ass);
            }
            return TwiPagesAssemblies[assemblyName];
        }

        /// <summary>
        /// 调用方法，获取结果值【后台调用使用】
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public static dynamic GetResult(AjaxModel model)
        {
            try
            {
                TwiLogHelper.Begin("TwiAjaxHelper.GetResult开始调用...");
                model.WriteLog();

                model.TwiPageNS = string.IsNullOrEmpty(model.TwiPageNS) ? TwiPageNS : model.TwiPageNS;
                string assemblyName = model.TwiPageNS;
                string strTypeName = string.Format("{0}.{1}", model.TwiPageNS, model.cn);
                if (!string.IsNullOrEmpty(model.mn))
                {
                    assemblyName = string.Format("{0}.{1}", model.TwiPageNS, model.mn);
                    strTypeName = string.Format("{0}.{1}.{2}", model.TwiPageNS, model.mn, model.cn);
                }

                if (TwiPageNS == "NoPrefix")
                {
                    strTypeName = model.cn;
                    assemblyName = model.mn;
                    strTypeName = string.Format("{0}.{1}", model.mn, model.cn);
                }

                Assembly ass = GetAssembly(assemblyName);
                Type t = ass.GetType(strTypeName);
                MethodInfo methodInfo = t.GetMethod(model.mn2, ActionBindingFlags);
                if (methodInfo == null)
                {
                    throw new Exception("未找到方法：" + model.mn2);
                }
                ParameterInfo[] paras = methodInfo.GetParameters();

                //参数和赋值
                object[] objParas = null;
                if (paras.Length > 0)
                {
                    objParas = new object[paras.Length];
                }

                for (int i = 0; i < paras.Length; i++)
                {
                    ParameterInfo pi = paras[i];
                    objParas[i] = model.dictParams[pi.Name];
                }

                object obj = null;
                if (string.IsNullOrEmpty(model.isStatic) || model.isStatic == "false" || model.isStatic == "0")
                {
                    obj = Activator.CreateInstance(t);
                }
                dynamic dyReturn = methodInfo.Invoke(obj, objParas);
                if (dyReturn != null)
                {
                    if (dyReturn is TwiReturn)
                    {
                        TwiLogHelper.Info("返回结果TwiReturn对象，序列化后为：\r\n\r\r" + JSSerialize.Serialize(dyReturn));
                    }
                    else {
                        TwiLogHelper.Info("返回结果：" + dyReturn.ToString());
                    }
                }
                else {
                    TwiLogHelper.Info("返回结果：NULL");
                }
                return dyReturn;
            }
            catch (Exception ex)
            {
                TwiLogHelper.Error(ex.Message);
                return ex.Message;
            }
            finally
            {                
                TwiLogHelper.End("TwiAjaxHelper.GetResult执行完成！\r\n=================================================================");
            }
            
        }


        /// <summary>
        /// 写请求参数日志
        /// </summary>
        /// <param name="context"></param>
        private static void WriteRequestFormLog(HttpContext context)
        {
            if (TwiLogHelper.GetTwiLogMode() == TwiLogModel.Debugger) 
            {
                string msg = "请求参数列表：";
                for (var i = 0; i < context.Request.Form.AllKeys.Length; i++)
                {
                    string key = context.Request.Form.AllKeys[i];
                    msg += string.Format("\r\n\t{0}:{1}",key,context.Request.Form[i]);
                }
                TwiLogHelper.Info(msg);
            }            
        }

        /// <summary>
        /// 检测方法是否需要判断会话权限
        /// </summary>
        /// <param name="mn2Format">格式：mn.cn.mn2</param>
        /// <returns></returns>
        private static bool CheckMn2IsOnRight(string mn2Format)
        {
            if (string.IsNullOrEmpty(TwiIgnoreRightMN2))
            {
                return true;
            }
            string[] mns = TwiIgnoreRightMN2.Split(',');
            string strFind = mns.FirstOrDefault(c => c == mn2Format);
            if (strFind == null)
            {
                return true;
            }
            return false;            
        }

        /// <summary>
        /// 将长日志改写成短日志
        /// </summary>
        /// <param name="twi"></param>
        /// <param name="hasWriteStrReturnLog"></param>
        private static void WriteLongToShortLog(TwiReturn twi,ref bool hasWriteStrReturnLog) {
            if (twi != null)
            {
                var dictTwiData = twi.data as IEnumerable<dynamic>;
                if (dictTwiData != null && dictTwiData.Count() > 1)
                {
                    object data = twi.data;
                    twi.data = new List<dynamic> { dictTwiData.FirstOrDefault() };
                    hasWriteStrReturnLog = true;
                    string str = JSSerialize.Serialize(twi);
                    string replaceStr = "],\"totalCount\":";
                    str = str.Replace(replaceStr, "...此处省略(" + (dictTwiData.Count() - 1) + ")条..." + replaceStr);
                    TwiLogHelper.Info("返回JSON字符串：" + str);
                    twi.data = data;
                }
            }
        }
    }
}
